#include "SFMLSpriteManager.h"
#include "..\Generic\Convert.h"
#include "..\Debug\DebugLog.h"
#include "..\Define.h"
#include "..\ScaleFactor.h"

using namespace vn;

SFMLSpriteManager::SFMLSpriteManager(unsigned int p_views)
{
	m_textureManager = new vn::SFMLTextureManager;
	m_fontManager = new SFMLFontManager;
	m_dataFilepaths.setPath("gfx.dat");
	m_dataFilepaths.parse();
	setViews(p_views);
}

SFMLSpriteManager::~SFMLSpriteManager(void)
{
	clearAllDrawables();
	delete m_textureManager;
	m_textureManager = nullptr;
	delete m_fontManager;
	m_fontManager = nullptr;
}

void SFMLSpriteManager::drawSprites(sf::RenderWindow& p_renderWindow)
{
	for (auto it = m_sprites.begin(); it != m_sprites.end(); it++)
	{
		if (!(*it).second.empty())
		{
			p_renderWindow.setView((*it).first);
			for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)
			{
				if ((*it2)->isVisible() && (*it2)->doRender())
					(*it2)->draw(p_renderWindow);
			}
		}
	}
}

void SFMLSpriteManager::drawSprites(sf::RenderTexture& p_renderTexture)
{
	for (auto it = m_sprites.begin(); it != m_sprites.end(); it++)
	{
		if (!(*it).second.empty())
		{
			p_renderTexture.setView((*it).first);
			for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)
			{
				if ((*it2)->isVisible())
					(*it2)->draw(p_renderTexture);
			}
		}
	}
}

vn::Sprite* SFMLSpriteManager::createSprite(unsigned int p_view, const std::string& p_id, float p_layer)
{
	SFMLSprite* sprite = new SFMLSprite(p_layer);
	std::string filepath = m_dataFilepaths.getFilepath(p_id);
	DataFilepath dataFilepath(filepath + ".dat");
	dataFilepath.parse();
	sprite->setTexture(m_textureManager->loadTexture(p_id, filepath + ".png", stringToBool(dataFilepath.getFilepath("repeat")), stringToBool(dataFilepath.getFilepath("smooth"))));
	sprite->setTextureRect(stringToVnIntRect(dataFilepath.getFilepath("size")));
	sprite->setOrigin(stringToVnVector2(dataFilepath.getFilepath("origin")));
	insertDrawable(sprite, p_view);
	return sprite;
}

vn::Text* SFMLSpriteManager::createText(unsigned int p_view, const std::string& p_fontID, const std::string& p_string, float p_layer)
{
	SFMLText* text = new SFMLText(p_layer);
	std::string filepath = m_dataFilepaths.getFilepath(p_fontID);
	text->setFont(m_fontManager->loadFont(p_fontID, filepath));
	text->setString(p_string);
	insertDrawable(text, p_view);
	return text;
}

vn::TileEngine* SFMLSpriteManager::createTiles(unsigned int p_view, const std::string& p_filepath, float p_layer)
{
	SFMLTileEngine* tileEngine = new SFMLTileEngine(p_layer);
	tileEngine->loadTiles(p_filepath);
	insertDrawable(tileEngine, p_view);
	return tileEngine;
}

vn::RectangleShape* SFMLSpriteManager::createRectangleShape(unsigned int p_view, const vn::Vector2& p_size, float p_layer)
{
	SFMLRectangleShape* rect = new SFMLRectangleShape(p_layer);
	rect->setSize(p_size);
	insertDrawable(rect, p_view);
	return rect;
}

inline void SFMLSpriteManager::insertDrawable(vn::SFMLDrawable* p_sprite, unsigned int p_view)
{
	if (p_view > m_sprites.size() - 1)
	{
		Debug::log("WARNING: view is out of range when adding Sprite. Sprite was added at back.");
		p_view = m_sprites.size() - 1;
	}

	if (!m_sprites[p_view].second.empty())
	{
		if (m_sprites[p_view].second.back()->getLayer() <= p_sprite->getLayer())
		{
			m_sprites[p_view].second.push_back(p_sprite);
		}
		else
		{
			for (auto it = m_sprites[p_view].second.begin(); it != m_sprites[p_view].second.end(); it++)
			{
				if ((*it)->getLayer() > p_sprite->getLayer())
				{
					m_sprites[p_view].second.insert(it, p_sprite);
					break;
				}
			}
		}
	}
	else
	{
		m_sprites[p_view].second.push_back(p_sprite);
	}
}

void SFMLSpriteManager::destroySprite(vn::SFMLSprite* p_sprite)
{
	bool stop = false;

	for (auto it = m_sprites.begin(); it != m_sprites.end(); it++)
	{
		if (!(*it).second.empty())
		{
			for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)
			{
				if (p_sprite == (*it2))
				{
					SFMLDrawable* temp = *it2;
					(*it).second.remove(temp);
					delete temp;
					temp = nullptr;
					stop = true;
					break;
				}
			}
		}
		if (stop)
			break;
	}
}

void SFMLSpriteManager::destroyTileEngine(vn::SFMLTileEngine* p_tileEngine)
{
	bool stop = false;

	for (auto it = m_sprites.begin(); it != m_sprites.end(); it++)
	{
		if (!(*it).second.empty())
		{
			for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)
			{
				if (p_tileEngine == (*it2))
				{
					SFMLDrawable* temp = *it2;
					(*it).second.remove(temp);
					delete temp;
					temp = nullptr;
					stop = true;
					break;
				}
			}
		}
		if (stop)
			break;
	}
}

void SFMLSpriteManager::destroyText(vn::SFMLText* p_text)
{
	bool stop = false;

	for (auto it = m_sprites.begin(); it != m_sprites.end(); it++)
	{
		if (!(*it).second.empty())
		{
			for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)
			{
				if (p_text == (*it2))
				{
					SFMLDrawable* temp = *it2;
					(*it).second.remove(temp);
					delete temp;
					temp = nullptr;
					stop = true;
					break;
				}
			}
		}
		if (stop)
			break;
	}
}

void SFMLSpriteManager::destroyRectangleShape(vn::SFMLRectangleShape* p_rectangleShape)
{
	bool stop = false;

	for (auto it = m_sprites.begin(); it != m_sprites.end(); it++)
	{
		if (!(*it).second.empty())
		{
			for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)
			{
				if (p_rectangleShape == (*it2))
				{
					SFMLDrawable* temp = *it2;
					(*it).second.remove(temp);
					delete temp;
					temp = nullptr;
					stop = true;
					break;
				}
			}
		}
		if (stop)
			break;
	}
}


void SFMLSpriteManager::clearAllDrawables()
{
	for (auto it = m_sprites.begin(); it != m_sprites.end(); it++)
	{
		if (!(*it).second.empty())
		{
			for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)
			{
				delete *it2;
				*it2 = nullptr;
			}
			(*it).second.clear();
		}
	}
}

void SFMLSpriteManager::setViews(unsigned int p_views)
{
	m_sprites.resize(p_views);
	for (auto it = m_sprites.begin(); it != m_sprites.end(); it++)
	{
		(*it).first.zoom(SCALEF);
		(*it).first.reset(sf::FloatRect(0.0f, 0.0f, VSW_SCALEF, VSH_SCALEF));
		(*it).first.setCenter(VSW_SCALEF_05, VSH_SCALEF_05);
	}
}

sf::View* SFMLSpriteManager::getView(unsigned int p_index)
{
	return &m_sprites[p_index].first;
}

void SFMLSpriteManager::setView(unsigned int p_view, sf::RenderWindow& p_renderWindow)
{
	p_renderWindow.setView(m_sprites[p_view].first);
}

void SFMLSpriteManager::setView(unsigned int p_view, sf::RenderTexture& p_renderTexture)
{
	p_renderTexture.setView(m_sprites[p_view].first);
}